package com.qd.system.service.user;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.db.BaseService;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.CacheKey;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.RedisTemplateUtil;
import com.qd.system.mapper.BaseUserInfoMapper;
import com.qd.system.model.BaseUserInfo;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 用户信息
 *
 * @author sjk
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class BaseUserInfoService extends BaseService<BaseUserInfoMapper, BaseUserInfo> {

    private static final String PREFIX_ID = "sys_base_userinfo_uid_{0}";
    private static final String PREFIX_UNIQUE_SYS_BASE_USER_INFO_MOBILE = "sys_base_userinfo_mobile_{0}";

    private final RedisTemplateUtil<BaseUserInfo> redisTemplateUtil;

    private final RedissonClient redissonClient;

    @Transactional(readOnly = true)
    @SneakyThrows
    public String getMobileToUid(String mobile) {
        if (!StringUtils.hasLength(mobile)) {
            throw new ApiException("手机号不能为空");
        }
        RLock lock = redissonClient.getLock("lock_"+mobile);
        if (log.isDebugEnabled()) {
            log.debug("lock: {}", lock);
        }
        try {
            try {
                boolean res = lock.tryLock(30, 10, TimeUnit.SECONDS);
                if (log.isDebugEnabled()) {
                    log.debug("res: {}", res);
                }
                if (res) {
                    BaseUserInfo baseUserinfo = getUniqueByMobile(mobile);
                    if (null == baseUserinfo) {
                        baseUserinfo = new BaseUserInfo();
                        baseUserinfo.setMobile(mobile);
                        save(baseUserinfo);
                        clearCache(baseUserinfo);
                    }
                    String uid = baseUserinfo.getUid();
                    baseUserinfo.freeData();
                    return uid;
                } else {
                    throw new ApiException(ApiResult.error());
                }
            } catch (InterruptedException e) {
                log.error("获得redis锁超时", e);
                Thread.currentThread().interrupt();
                throw new ApiException("获得redis锁超时");
            } catch (Exception e) {
                log.error("err. ", e);
                throw new ApiException(e);
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * 删除，单个
     *
     * @param uid 主键
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeById(String uid) {
        final BaseUserInfo model = Optional.ofNullable(getById(uid)).orElseThrow(() -> new ApiException("数据不存在,不能删除"));
        try {
            if (!super.removeById(uid)) {
                throw new ApiException("删除失败");
            }
        } finally {
            clearCache(model);
            model.freeData();
        }
    }

    /**
     * 根据主键判断数据是否存在
     *
     * @param uid 主键
     * @return 存在为true
     */
    @Transactional(readOnly = true)
    public Boolean isExistsById(String uid) {
        boolean exists = false;
        if (StringUtils.hasLength(uid)) {
            final BaseUserInfo model = getById(uid);
            exists = (null != model);
            if (exists) {
                model.freeData();
            }
        }
        return exists;
    }

    /**
     * 根据主键获取数据
     *
     * @param uid 主键
     * @return 单条记录
     */
    @Transactional(readOnly = true)
    public BaseUserInfo getById(String uid) {
        final String key = RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, uid);
        return redisTemplateUtil.get(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY), () -> super.getById(uid), BaseUserInfo.class);
    }

    /**
     * 根据唯一性索引获得数据
     * <p>
     * param mobile
     *
     * @return 单条数据
     */
    @Transactional(readOnly = true)
    public BaseUserInfo getUniqueByMobile(String mobile) {
        final QueryWrapper<BaseUserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile);
        final String key = RedisTemplateUtil.getRedisCacheKey(PREFIX_UNIQUE_SYS_BASE_USER_INFO_MOBILE, mobile);
        final BaseUserInfo model = redisTemplateUtil.get(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY), () -> super.getOne(queryWrapper, false), BaseUserInfo.class);
        queryWrapper.clear();
        return model;
    }

    /**
     * 清空缓存
     *
     * @param model 数据库对象
     */
    public void clearCache(BaseUserInfo model) {
        if (null == model) {
            return;
        }
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, model.getUid()));
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.getRedisCacheKey(PREFIX_UNIQUE_SYS_BASE_USER_INFO_MOBILE, model.getMobile()));
    }
}